#pragma once

#include "loirey_GLOBAL.h"
#include "loirey_BasicStructure.h"
#include "loirey_MyMath.h"

namespace loirey
{
	class CCacheManager
	{
	private:
		__int64 __EmptyIndex;
	public:
		size_t CacheSize;
		size_t ItemAmount;
		CSimpleTypeArray<__int64> c2i;
		CSimpleTypeArray<__int64> i2c;

	public:
		virtual __int64 SelectRoomToKick(__int64 NewItemIndex) = 0;
	public:
		virtual void myInit(size_t CacheSize, size_t ItemAmount);
		virtual void Clear();
		virtual void IncreaseItemAmountBy(size_t Amount);
		virtual void ErasePosition(__int64 PositionIndex);
		virtual __int64 FindItem(__int64 ItemIndex);
		virtual void RemoveItem(__int64 ItemIndex);
		virtual __int64 GetItemPosition(__int64 ItemIndex, __int64& DstLastItemIndex);
	};

	class CRandomCacheManager : public CCacheManager
	{
	public:
		__int64 SelectRoomToKick(__int64 NewItemIndex);
	};

	template<typename TData>
	class CRandomCachePool
	{
	private:
		__int64 __EmptyIndex;
	public:
		__int64 PoolSize;
		__int64 DataAmount;
		__int64* pData2Cache;
		__int64* pCache2Data;
		TData* CachePool;

	protected:
		void myRelease()
		{
			PoolSize = 0;
			DataAmount = 0;
			CDataStructureTools::MyRelease_List(pData2Cache);
			CDataStructureTools::MyRelease_List(pCache2Data);
			CDataStructureTools::MyRelease_List(CachePool);
		}
	public:
		CRandomCachePool()
		{
			PoolSize = 0;
			DataAmount = 0;
			pData2Cache = NULL;
			pCache2Data = NULL;
			CachePool = NULL;
		}
		~CRandomCachePool()
		{
			myRelease();
		}
		void myInit(__int64 PoolSize, __int64 DataAmount)
		{
			myRelease();

			if (PoolSize < 1)
				PoolSize = DataAmount;

			this->DataAmount = DataAmount;
			this->PoolSize = PoolSize;
			pData2Cache = new __int64 [DataAmount];
			pCache2Data = new __int64 [PoolSize];
			CachePool = new TData [PoolSize];
			Clear();
		}
		void Clear()
		{
			__int64 i;

			for ( i = 0; i < DataAmount; ++i )
				pData2Cache[i] = PoolSize;
			for ( i = 0; i < PoolSize; ++i )
				pCache2Data[i] = DataAmount;
			__EmptyIndex = 0;
		}
		TData* GetData(__int64 DataIndex, __int64& dstLastDataIndex)
		{
			TData* ret = NULL;
			__int64 i;
			
			if (DataIndex<0 || DataIndex>=DataAmount)
			{
				ret = NULL;
				dstLastDataIndex = -1;
			}
			else 
				if ((i = pData2Cache[DataIndex]) < PoolSize)
				{
					ret = CachePool + pData2Cache[DataIndex];
					dstLastDataIndex = DataIndex;
				}
				else
					if ((i = __EmptyIndex) < PoolSize)
					{
						ret = CachePool + i;
						dstLastDataIndex = -1;

						++__EmptyIndex;
						pCache2Data[i] = DataIndex;
						pData2Cache[DataIndex] = i;
					}
					else
					{
						i = CMyRandom::NextInt64(PoolSize);

						ret = CachePool + i;
						dstLastDataIndex = pCache2Data[i];

						pData2Cache[dstLastDataIndex] = PoolSize;
						pCache2Data[i] = DataIndex;
						pData2Cache[DataIndex] = i;
					}
			return ret;
		}
	};

};

